import Protocol from './Protocol'
import { ProtocolCmd, ProtocolResult, ProtocolPacket, ProtocolSensorInfo, ProtocolSensorType, ProtocolSensorDateType, ProtocolSensorData, ProtocolIrrPlanType, ProtocolIrrPlanDateType, ProtocolIrrPlanTimer, ProtocolIrrPlanThreshold } from './Protocol'
import TcpProcess from "./TcpProcess"


export type AgriculturaSystemData_WaterInfo = {
  status: boolean,  // 水阀当前状态
}

// 监测点
export type AgriculturaSystemData_Monitor = {
  id: string,         // 监测点编号
  name: string,       // 监测点名称
  market: string,     // 监测点备注
  sensor: ProtocolSensorInfo,                     // 传感器信息
  sensor_history_data: Array<ProtocolSensorData>, // 传感器历史数据
  water: AgriculturaSystemData_WaterInfo,         // 水阀信息列表
  irr_type: ProtocolIrrPlanType,                  // 灌溉计划类型
  irr_timer: Array<ProtocolIrrPlanTimer>,         // 灌溉计划-定时
  irr_threshold: Array<ProtocolIrrPlanThreshold>, // 灌溉计划-阈值
}

class AgriculturalSystemData {
  // 定时器，用于解析接收到的字符串
  private intervalId_recvstr: number = 0
  // 存放网络接收到的字符串
  private string_recv: string = ""

  // 定时器，用于搜集所有监测点
  private intervalId_searchAllMonitor: number = 0
  // 定时器，用于获知某个监测点的所有传感器数据
  private intervalId_getAllSensorInfo: number = 0

  // 是否登录成功
  private login_successful: boolean = false
  // 是否更改密码
  private login_change_password: boolean = false

  public monitor: Array<AgriculturaSystemData_Monitor> = []
  public monitor_select: number = 0

  /***************************************************************
   * 函数名称: constructor
   * 说    明: 类初始化时，触发该函数
   * 参    数: 无
   * 返 回 值: 无
   ***************************************************************/
  constructor() {
    TcpProcess.init()
    this.intervalId_recvstr = setInterval(this.recvPacketProcess, 200)
  }

  /***************************************************************
   * 函数名称: init
   * 说    明: 类内部参数初始化
   * 参    数: 无
   * 返 回 值: 无
   ***************************************************************/
  init() {
    this.string_recv = ""
    this.login_successful = false
    this.login_change_password = false
  }

  /***************************************************************
   * 函数名称: delay_msec
   * 说    明: 时间等待，单位为毫秒
   * 参    数: 无
   * 返 回 值: 无
   ***************************************************************/
  delay_msec(msec: number) {
    return new Promise(resolve => setTimeout(resolve, msec))
  }

  /***************************************************************
   * 函数名称: pushString
   * 说    明: 将str添加到this.string_recv的队列尾
   * 参    数: 无
   * 返 回 值: 无
   ***************************************************************/
  pushString(str: string) {
    this.string_recv += str
  }

  /***************************************************************
   * 函数名称: monitorPush
   * 说    明: 添加监测点
   * 参    数: 无
   * 返 回 值: 无
   ***************************************************************/
  monitorPush(id: string, name: string, market: string) {
    let i: number = 0
    for (i = 0; i < this.monitor.length; i++) {
      // 已有该监测点编号
      if (id === this.monitor[i].id) {
        return
      }
    }
    // 列表中没有该监测点编号
    if (i >= this.monitor.length) {
      let sensor_info: ProtocolSensorInfo = {
        temperature: 40.0,    // 温度
        humidity: 40.0,       // 湿度
        co2: 20.0,            // 二氧化碳浓度
        lumination: 20.0,     // 光照强度
        soil_humidity: 20.0,  // 土壤湿度
      }
      let point: AgriculturaSystemData_Monitor = {
        id: id,
        name: name,
        market: market,
        sensor: sensor_info,
        sensor_history_data: [],
        water: {
          status: false,
        },
        irr_type: ProtocolIrrPlanType.ProtocolIrrPlanType_Manual,
        irr_timer: [],
        irr_threshold: [],
      }
      this.monitor.push(point)
      return
    }
  }


  /***************************************************************
   * 函数名称: setMonitorSelect
   * 说    明: 通过monitor_id找到对应的this.monitor索引
   * 参    数: 无
   * 返 回 值: 无
   ***************************************************************/
  setMonitorSelect(monitor_id: string) {
    let i: number = 0
    for (i = 0; i < this.monitor.length; i++) {
      if (monitor_id === this.monitor[i].id) {
        this.monitor_select = i
        return
      }
    }
    if (i >= this.monitor.length) {
      console.error(`AgriculturalSystemData: setMonitorSelect() => monitor_id(${monitor_id}) is out of the range`)
      return
    }
  }


  /***************************************************************
   * 函数名称: checkMonitorSelect
   * 说    明: 检查当前monitor_select是否合法
   * 参    数: 无
   * 返 回 值: 无
   ***************************************************************/
  checkMonitorSelect() : boolean {
    if (this.monitor.length <= 0) {
      return false
    }
    if (this.monitor_select >= this.monitor.length) {
      return false
    }
    return true
  }


  /***************************************************************
   * 函数名称: getIndexMonitorFromId
   * 说    明: 通过id获取this.monitor数组的索引
   * 参    数:
   *      @id   监测点的编号
   * 返 回 值: 返回this.monitor数组的索引，-1为错误，>=0为成功
   ***************************************************************/
  getIndexMonitorFromId(id: string) : number {
    let i: number = 0
    for (i = 0; i < this.monitor.length; i++) {
      if (id === this.monitor[i].id) {
        return i
      }
    }
    return -1
  }


  /***************************************************************
   * 函数名称: sensorHistoryDataPush
   * 说    明: 添加传感器数据到对应的this.monitor数组中
   * 参    数:
   *        @id           监测点编号
   *        @sensor_data  该监测点的传感器历史数据
   * 返 回 值: 无
   ***************************************************************/
  sensorHistoryDataPush(id: string, sensor_data: ProtocolSensorData) {
    let i: number = 0
    for (i = 0; i < this.monitor.length; i++) {
      if (id === this.monitor[i].id) {
        let offset: number = 0
        for (offset = 0; offset < this.monitor[i].sensor_history_data.length; offset++) {
          let date_type: ProtocolSensorDateType = this.monitor[i].sensor_history_data[offset].date_type
          let sensor_type: ProtocolSensorType = this.monitor[i].sensor_history_data[offset].sensor_type
          if ((date_type == sensor_data.date_type) && (sensor_type == sensor_data.sensor_type)) {
            this.monitor[i].sensor_history_data[offset].data = sensor_data.data
            break
          }
        }
        if (offset >= this.monitor[i].sensor_history_data.length) {
          // 添加
          this.monitor[i].sensor_history_data.push(sensor_data)
        }
        return
      }
    }
    if (i >= this.monitor.length) {
      console.error(`AgriculturalSystemData: sensorHistoryDataPush() => id(${id}) is out of the range`)
      return
    }
  }

  /***************************************************************
   * 函数名称: sensorHistoryDataGet
   * 说    明: 视图层获取传感器历史数据的接口
   * 参    数:
   *      @sensor_type    传感器类型
   *      @date_type      传感器历史数据时间类型
   * 返 回 值:
   *      @result         返回结果，true为成功，反之为失败
   *      @sensor_data    传感器历史数据内容
   ***************************************************************/
  sensorHistoryDataGet(sensor_type: ProtocolSensorType, date_type: ProtocolSensorDateType) : { result: boolean, sensor_data: ProtocolSensorData } {
    let sensor_data_temp: ProtocolSensorData = {
      date_type: date_type,
      sensor_type: sensor_type,
      data: [],
    }

    if (this.checkMonitorSelect() != true) {
      console.error(`AgriculturalSystemData: sensorHistoryDataGet() => checkMonitorSelect failed`)
      return { result: false, sensor_data: sensor_data_temp }
    }

    let history_data: Array<ProtocolSensorData> = this.monitor[this.monitor_select].sensor_history_data
    let i: number = 0
    for (i = 0; i < history_data.length; i++) {
      if ((sensor_type == history_data[i].sensor_type) && (date_type == history_data[i].date_type)) {
        // 核对正确，直接返回
        return { result: true, sensor_data: history_data[i] }
      }
    }

    // 没有找到对应的内容
    console.error(`AgriculturalSystemData: sensorHistoryDataGet() => sensor_type(${sensor_type}) or date_type(${date_type}) is out of the range`)
    return { result: false, sensor_data: sensor_data_temp }
  }

  /***************************************************************
   * 函数名称: waterUpdateStatue
   * 说    明: 更新水阀状态
   * 参    数:
   *      @monitor_id     监测点编号
   *      @water_status   水阀状态
   * 返 回 值: 无
   ***************************************************************/
  waterUpdateStatue(monitor_id: string, water_status: boolean) {
    let monitor_index: number = this.getIndexMonitorFromId(monitor_id)
    if (monitor_index < 0) {
      console.error(`AgriculturalSystemData: waterUpdateStatue() => monitor_id(${monitor_id}) is out of the range`)
      return
    } else {
      this.monitor[monitor_index].water.status = water_status
    }
  }

  /***************************************************************
   * 函数名称: recvPacketProcess
   * 说    明: 该函数主要负责将this.string_recv中的字符串进行报文解析
   * 参    数: 无
   * 返 回 值: 无
   ***************************************************************/
  recvPacketProcess = () : void => {
    while (1) {
      let find_res: { result: boolean, start: number, length: number } = Protocol.findStr2Packet(this.string_recv)
      if (find_res.result != true) {
        break
      }
      // 将符合报文的字符串取出来
      let str: string = this.string_recv.substring(find_res.start, find_res.start + find_res.length)
      // 从string_recv的队列头将str内容剔除
      this.string_recv = this.string_recv.substring(find_res.start + find_res.length)
      // 解析字符串
      console.log(`AgriculturalSystemData: recvPacketProcess() => result = ${find_res.result}`)
      console.log(`AgriculturalSystemData: recvPacketProcess() => start = ${find_res.start}, length = ${find_res.length}`)
      console.log(`AgriculturalSystemData: recvPacketProcess() => str = ${str}`)
      let res: { result: boolean, packet: ProtocolPacket } = Protocol.parsePacket(str)
      if (res.result != true) {
        console.error(`AgriculturalSystemData: recvPacketProcess() => Protocol.parsePacket failed`)
        continue
      }
      console.log(`AgriculturalSystemData: recvPacketProcess() => res.packet.cmd = ${res.packet.cmd}`)

      switch (res.packet.cmd) {
        case ProtocolCmd.ProtocolCmd_Login:
          {
            let rsp: { result: boolean } = Protocol.loginRsp(res.packet)
            this.login_successful = rsp.result
          }
          break

        case ProtocolCmd.ProtocolCmd_ChangePassWord:
          {
            let rsp: { result: boolean } = Protocol.changePassWordRsp(res.packet)
            this.login_change_password = rsp.result
          }
          break

        case ProtocolCmd.ProtocolCmd_ResetPassWord:
          {
            let rsp: { result: boolean } = Protocol.resetPassWordRsp(res.packet)
          }
          break

        case ProtocolCmd.ProtocolCmd_SearchAllMonitoring:
          {
            let rsp: { result: boolean, id: string, name: string, market: string } = Protocol.searchAllMonitoringRsp(res.packet)
            if (rsp.result != true) {
              console.error(`AgriculturalSystemData: recvPacketProcess() => Protocol.searchAllMonitoringRsp failed`)
              break
            }
            this.monitorPush(rsp.id, rsp.name, rsp.market)
          }
          break

        case ProtocolCmd.ProtocolCmd_GetAllSensorInfo:
          {
            let rsp: { result: boolean, id: string, sensor: ProtocolSensorInfo } = Protocol.getAllSensorInfoRsp(res.packet)
            if (rsp.result != true) {
              console.error(`AgriculturalSystemData: recvPacketProcess() => Protocol.searchAllMonitoringRsp failed`)
              break
            }
            let i: number = 0
            for (i = 0; i < this.monitor.length; i++) {
              if (rsp.id === this.monitor[i].id) {
                this.monitor[i].sensor = rsp.sensor
                break
              }
            }
            if (i >= this.monitor.length) {
              console.error(`AgriculturalSystemData: recvPacketProcess() => id(${rsp.id}) is not monitor`)
              break
            }
          }
          break

        case ProtocolCmd.ProtocolCmd_GetAllSensorHistoryData:
          {
            console.log(`AgriculturalSystemData: recvPacketProcess() => ProtocolCmd_GetAllSensorHistoryData, res.packet.data.length = ${res.packet.data.length}`)
            let rsp: { result: boolean, id: string, sensor_data: ProtocolSensorData } = Protocol.getAllSensorHistoryDataRsp(res.packet)
            if (rsp.result != true) {
              console.error(`AgriculturalSystemData: recvPacketProcess() => ProtocolCmd_GetAllSensorHistoryData, Protocol.getAllSensorHistoryDataRsp failed`)
              break
            }
            this.sensorHistoryDataPush(rsp.id, rsp.sensor_data)
            console.log(`AgriculturalSystemData: recvPacketProcess() => ProtocolCmd_GetAllSensorHistoryData, sensorHistoryDataPush`)
          }
          break

        case ProtocolCmd.ProtocolCmd_ControlWater:
          {
            let rsp: { result: boolean, id: string, water_is_on: boolean } = Protocol.controlWaterRsp(res.packet)
            if (rsp.result != true) {
              console.error(`AgriculturalSystemData: recvPacketProcess() => Protocol.controlWaterRsp failed`)
              break
            }
            this.waterUpdateStatue(rsp.id, rsp.water_is_on)
          }
          break

        case ProtocolCmd.ProtocolCmd_GetIrrigatePlan:
          {
            let rsp: { result: boolean, id: string, irr_type: ProtocolIrrPlanType,  timer: Array<ProtocolIrrPlanTimer>, threshold: Array<ProtocolIrrPlanThreshold> } = Protocol.getIrrigatePlanRsp(res.packet)
            if (rsp.result != true) {
              console.error(`AgriculturalSystemData: recvPacketProcess() => Protocol.controlWaterRsp failed`)
              break
            }
            let monitor_index: number = this.getIndexMonitorFromId(rsp.id)
            if (monitor_index < 0) {
              console.error(`AgriculturalSystemData: recvPacketProcess() => Protocol.getIndexMonitorFromId failed and rsp.id(${rsp.id})`)
              break
            }
            switch (rsp.irr_type) {
              case ProtocolIrrPlanType.ProtocolIrrPlanType_Manual:
                {
                  this.monitor[monitor_index].irr_type = rsp.irr_type
                }
                break

              case ProtocolIrrPlanType.ProtocolIrrPlanType_Timer:
                {
                  this.monitor[monitor_index].irr_type = rsp.irr_type
                  this.monitor[monitor_index].irr_timer = rsp.timer
                }
                break

              case ProtocolIrrPlanType.ProtocolIrrPlanType_Threshold:
                {
                  this.monitor[monitor_index].irr_type = rsp.irr_type
                  this.monitor[monitor_index].irr_threshold = rsp.threshold
                }
                break

              default:
                console.error(`AgriculturalSystemData: recvPacketProcess() => irr_type(${rsp.irr_type}) is out of the range`)
                break;
            }
          }
          break

        case ProtocolCmd.ProtocolCmd_SetIrrigatePlan:
          {
            let rsp: { result: boolean, id: string } = Protocol.setIrrigatePlanRsp(res.packet)
            if (rsp.result != true) {
              console.error(`AgriculturalSystemData: recvPacketProcess() => Protocol.setIrrigatePlanRsp failed`)
              break
            }
          }
          break

        default:
          console.error(`AgriculturalSystemData: recvPacketProcess() => cmd(${res.packet.cmd}) is out of the range`)
          break
      }
    }
  }


  /***************************************************************
   * 函数名称: login
   * 说    明: 验证用户名和密码是否正确
   * 参    数:
   *        @user       用户名
   *        @password   密码
   * 返 回 值: true为正确，反之为错误
   ***************************************************************/
  login(user: string, password: string) : boolean {
    // 生成协议报文
    let res: { result: boolean, str: string } = Protocol.login(user, password)
    if (res.result != true) {
      console.error("AgriculturalSystemData: login() => Protocol.login() failed")
      return false
    }
    // 发送字符串
    TcpProcess.tcp_send(res.str)
    // 等待
    this.delay_msec(500)
    // 检查
    return this.login_successful
  }

  /***************************************************************
   * 函数名称: changePassWord
   * 说    明: 修改密码命令
   * 参    数:
   *        @user           用户名
   *        @password_old   旧密码
   *        @password_new   新密码
   * 返 回 值: true为正确，反之为错误
   ***************************************************************/
  changePassWord(user: string, password_old: string, password_new: string) : boolean {
    // 生成协议报文
    let res: { result: boolean, str: string } = Protocol.changePassWord(user, password_old, password_new)
    if (res.result != true) {
      console.error("AgriculturalSystemData: login() => Protocol.changePassWord() failed")
      return false
    }
    // 发送字符串
    TcpProcess.tcp_send(res.str)
    // 等待
    this.delay_msec(500)
    // 检查
    return true
  }

  /***************************************************************
   * 函数名称: resetPassWord
   * 说    明: 重置密码
   * 参    数:
   *        @user     用户名
   *        @email    电子邮箱地址
   * 返 回 值: true为正确，反之为错误
   ***************************************************************/
  resetPassWord(user: string, email: string) : boolean {
    // 生成协议报文
    let res: { result: boolean, str: string } = Protocol.resetPassWord(user, email)
    if (res.result != true) {
      console.error("AgriculturalSystemData: changePassWord() => Protocol.resetPassWord() failed")
      return false
    }
    // 发送字符串
    TcpProcess.tcp_send(res.str)
    return true
  }


  /***************************************************************
   * 函数名称: searchAllMonitoring
   * 说    明: 搜集所有监测点
   * 参    数:
   * 返 回 值: true为正确，反之为错误
   ***************************************************************/
  searchAllMonitoring() : boolean {
    // 生成协议报文
    let res: { result: boolean, str: string } = Protocol.searchAllMonitoring()
    if (res.result != true) {
      console.error("AgriculturalSystemData: searchAllMonitoring() => Protocol.searchAllMonitoring() failed")
      return false
    }
    // 发送字符串
    TcpProcess.tcp_send(res.str)
    return true
  }


  /***************************************************************
   * 函数名称: getAllSensorInfo
   * 说    明: 获知某个监测点传感器数据
   * 参    数:
   * 返 回 值: true为正确，反之为错误
   ***************************************************************/
  getAllSensorInfo() : boolean {
    if (this.checkMonitorSelect() != true) {
      console.error("AgriculturalSystemData: getAllSensorInfo() => checkMonitorSelect failed")
      return false
    }
    // 生成协议报文
    let res: { result: boolean, str: string } = Protocol.getAllSensorInfo(this.monitor[this.monitor_select].id)
    if (res.result != true) {
      console.error("AgriculturalSystemData: searchAllMonitoring() => Protocol.getAllSensorInfo() failed")
      return false
    }
    // 发送字符串
    TcpProcess.tcp_send(res.str)
    // 等待
    this.delay_msec(100)
    return true
  }


  /***************************************************************
   * 函数名称: getAllSensorHistoryData
   * 说    明: 搜集某个监测点历史数据
   * 参    数:
   * 返 回 值: true为正确，反之为错误
   ***************************************************************/
  getAllSensorHistoryData(date_type: ProtocolSensorDateType) : boolean {
    if (this.checkMonitorSelect() != true) {
      console.error("AgriculturalSystemData: getAllSensorHistoryData() => checkMonitorSelect failed")
      return false
    }
    // 生成协议报文
    let id: string = this.monitor[this.monitor_select].id
    let sensor_type: ProtocolSensorType = ProtocolSensorType.ProtocolSensorType_Temperature
    for (sensor_type = ProtocolSensorType.ProtocolSensorType_Temperature; sensor_type < ProtocolSensorType.ProtocolSensorType_Max; sensor_type++) {
      let res: { result: boolean, str: string } = Protocol.getAllSensorHistoryData(id, sensor_type, date_type)
      if (res.result != true) {
        console.error("AgriculturalSystemData: getAllSensorHistoryData() => Protocol.getAllSensorHistoryData() failed")
        return false
      }
      // 发送字符串
      TcpProcess.tcp_send(res.str)
      // console.log(`AgriculturalSystemData: getAllSensorHistoryData() => res.str = ${res.str}`)
      // 等待100微秒
      this.delay_msec(100)
    }
    return true
  }


  /***************************************************************
   * 函数名称: controlWater
   * 说    明: 控制某监测点的水阀开关
   * 参    数:
   * 返 回 值: true为正确，反之为错误
   ***************************************************************/
  controlWater(water_is_on: boolean) : boolean {
    if (this.checkMonitorSelect() != true) {
      console.error("AgriculturalSystemData: controlWater() => checkMonitorSelect failed")
      return false
    }
    // 生成协议报文
    let res: { result: boolean, str: string } = Protocol.controlWater(this.monitor[this.monitor_select].id, water_is_on)
    if (res.result != true) {
      console.error("AgriculturalSystemData: controlWater() => Protocol.controlWater() failed")
      return false
    }
    // 发送字符串
    TcpProcess.tcp_send(res.str)
    return true
  }


  /***************************************************************
   * 函数名称: getIrrigatePlan
   * 说    明: 获知灌溉计划
   * 参    数:
   * 返 回 值: true为正确，反之为错误
   ***************************************************************/
  getIrrigatePlan() : boolean {
    if (this.checkMonitorSelect() != true) {
      console.error("AgriculturalSystemData: getIrrigatePlan() => checkMonitorSelect failed")
      return false
    }
    // 生成协议报文
    let res: { result: boolean, str: string } = Protocol.getIrrigatePlan(this.monitor[this.monitor_select].id)
    if (res.result != true) {
      console.error("AgriculturalSystemData: getIrrigatePlan() => Protocol.controlWater() failed")
      return false
    }
    // 发送字符串
    TcpProcess.tcp_send(res.str)
    // 等待
    this.delay_msec(100)
    return true
  }


  /***************************************************************
   * 函数名称: setIrrigatePlan_Manual
   * 说    明: 设置灌溉计划
   * 参    数:
   * 返 回 值: true为正确，反之为错误
   ***************************************************************/
  setIrrigatePlan_Manual() : boolean {
    if (this.checkMonitorSelect() != true) {
      console.error("AgriculturalSystemData: setIrrigatePlan_Manual() => checkMonitorSelect failed")
      return false
    }
    // 生成协议报文
    let res: { result: boolean, str: string } = Protocol.setIrrigatePlan_Manual(this.monitor[this.monitor_select].id)
    if (res.result != true) {
      console.error("AgriculturalSystemData: setIrrigatePlan_Manual() => Protocol.setIrrigatePlan_Manual() failed")
      return false
    }
    // 发送字符串
    TcpProcess.tcp_send(res.str)
    return true
  }

  /***************************************************************
   * 函数名称: setIrrigatePlan_Timer
   * 说    明: 设置灌溉计划
   * 参    数:
   *        @timer    定时器灌溉计划数组
   * 返 回 值: true为正确，反之为错误
   ***************************************************************/
  setIrrigatePlan_Timer(timer: Array<ProtocolIrrPlanTimer>) : boolean {
    if (this.checkMonitorSelect() != true) {
      console.error("AgriculturalSystemData: setIrrigatePlan_Timer() => checkMonitorSelect failed")
      return false
    }
    // 生成协议报文
    let res: { result: boolean, str: string } = Protocol.setIrrigatePlan_Timer(this.monitor[this.monitor_select].id, timer)
    if (res.result != true) {
      console.error("AgriculturalSystemData: setIrrigatePlan_Timer() => Protocol.setIrrigatePlan_Manual() failed")
      return false
    }
    // 发送字符串
    TcpProcess.tcp_send(res.str)
    return true
  }

  /***************************************************************
   * 函数名称: setIrrigatePlan_Threshold
   * 说    明: 设置灌溉计划-阈值
   * 参    数:
   *      @threshold    阈值灌溉计划数组
   * 返 回 值: true为正确，反之为错误
   ***************************************************************/
  setIrrigatePlan_Threshold(threshold: Array<ProtocolIrrPlanThreshold>) : boolean {
    if (this.checkMonitorSelect() != true) {
      console.error("AgriculturalSystemData: setIrrigatePlan_Threshold() => checkMonitorSelect failed")
      return false
    }
    // 生成协议报文
    let res: { result: boolean, str: string } = Protocol.setIrrigatePlan_Threshold(this.monitor[this.monitor_select].id, threshold)
    if (res.result != true) {
      console.error("AgriculturalSystemData: setIrrigatePlan_Threshold() => Protocol.setIrrigatePlan_Manual() failed")
      return false
    }
    // 发送字符串
    TcpProcess.tcp_send(res.str)
    return true
  }

}

export default new AgriculturalSystemData()
